package com.sunflower.common.mybatis.core.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.sunflower.common.core.utils.MapstructUtils;
import com.sunflower.common.core.utils.StringUtils;
import com.sunflower.common.mybatis.core.domain.Id;
import com.sunflower.common.mybatis.core.mapper.BaseMapperPlus;
import com.sunflower.common.mybatis.core.page.ISorting;
import com.sunflower.common.mybatis.core.page.PageQuery;
import com.sunflower.common.mybatis.core.page.TableDataInfo;
import com.sunflower.common.mybatis.core.service.IBoService;
import com.sunflower.common.mybatis.metadata.CustomOrderItem;
import com.sunflower.common.mybatis.query.CustomQueryWrapper;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * @author: SunLuQuan
 * @Date: 2024年03月24日 18:18
 * @Description: BoServiceImpl
 * TODO
 */
public class BoServiceImpl<T, M extends BaseMapperPlus<T, V>, V, B> extends ServiceImpl<T, M, V> implements IBoService<T, V, B> {

    @Override
    public V queryById(Serializable id) {
        return getBaseMapper().selectVoById(id);
    }

    @Override
    public TableDataInfo<V> queryPageList(B bo, PageQuery pageQuery, boolean isSort, SFunction<T, ?>... columns) {
        LambdaQueryWrapper<T> queryWrapper = buildQueryWrapper(bo, isSort);
        if (ArrayUtil.isNotEmpty(columns)) {
            queryWrapper.select(columns);
        }
        IPage<V> page = getBaseMapper().selectVoPage(pageQuery.build(), queryWrapper);

        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<V> queryPageList(B bo, PageQuery pageQuery, SFunction<T, ?>... columns) {
        return queryPageList(bo, pageQuery, false, columns);
    }

    protected LambdaQueryWrapper<T> buildQueryWrapper(B bo) {
        return buildQueryWrapper(bo, true);
    }

    /**
     * @param bo
     * @param buildSort 是否构建排序，当查询为分页的时候不需要构建排序
     * @return
     */
    protected LambdaQueryWrapper<T> buildQueryWrapper(B bo, boolean buildSort) {
        T entity = MapstructUtils.convert(bo, getEntityClass());
        if (buildSort && bo instanceof ISorting sorting) {
            List<OrderItem> orders = sorting.orders();
            if (CollectionUtil.isNotEmpty(orders)) {
                CustomQueryWrapper<T> queryWrapper = new CustomQueryWrapper<>(entity);
                for (OrderItem order : orders) {
                    if (order instanceof CustomOrderItem customOrderItem) {
                        queryWrapper.orderBy(true, order.isAsc(), order.getColumn(), customOrderItem.getOrderSqlSegment());
                    } else {
                        queryWrapper.orderBy(true, order.isAsc(), order.getColumn());
                    }
                }
                return queryWrapper.lambda();
            }
        }
        return Wrappers.lambdaQuery(entity);
    }

    @Override
    public List<V> queryList(B bo) {
        return getBaseMapper().selectVoList(buildQueryWrapper(bo));
    }

    @Override
    public Boolean insertByBo(B bo) {
        T add = MapstructUtils.convert(bo, getEntityClass());
        /**
         * TODO 如果需要获取 新增后的自增编号 需要重写此方法
         * bo.setId(add.getId());
         */
        boolean flag = insert(add);
        if (add instanceof Id idAdd) {
            Object id = idAdd.getId();
            if (bo instanceof Id idBo) {
                idBo.setId(id);
            }
        }
        return flag;
    }

    @Override
    public Boolean updateByBo(B bo) {
        T update = MapstructUtils.convert(bo, getEntityClass());
        return updateById(update);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Serializable> ids) {
        return deleteByIds(ids);
    }
}
